package com.wxm.api.xml;

import com.wxm.api.exception.CrawlerException;
import com.wxm.jsoup.util.JsoupUtils;
import lombok.Getter;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * <p>
 *      爬虫xml容器类
 * </p>
 *
 * @author wxm
 * @Date 2021/9/29
 */
@Getter
public class CrawlerFiledContainer extends Container{
    /**
     * 实体类属性名称
     */
    private String fieldName;

    /**
     * 需要获取的属性值 如果没有就获取标签中的text
     */
    private String attr;

    /**
     * 是否必须
     */
    private Boolean must;

    @Override
    public void fillAttribute(org.dom4j.Element element) {
        this.fieldName = this.getStringValue( element.attributeValue("fieldName"));
        if (this.fieldName == null){
            this.fieldName = element.getText().trim();
        }

        this.attr = this.getStringValue(element.attributeValue("attr"));
        this.must = this.getBooleanValue(true,element.attributeValue("must"));
    }

    @Override
    protected void judgeAttributeNull() {
        if (null == this.select) CrawlerException.error("缺失 select属性");
        if (null == this.index) CrawlerException.error("缺失 index属性");
        if (this.collection && this.collectionIndex == null) CrawlerException.error("缺失 collectionIndex属性");
    }

    @Override
    @SuppressWarnings("all")
    public Object fillHtmlObject(Element element, Object o) {
        String[] selectSplit = this.select.split(";");
        String[] indexSplit = this.index.split(";");
        try {
            Object value = null;
            if (this.collection){
                //集合类型 得到父级解析出来的集合
                Elements es = JsoupUtils.getElementIndexs(element, selectSplit, indexSplit);
                List<Object> list = new ArrayList<>(es.size());

                for (Element e : es) {
                    if (this.clazz != null){
                        Object o1 = this.clazz.newInstance();
                        for (CrawlerFiledContainer child : this.children) {
                            child.fillHtmlObject(e, o1);
                        }
                        list.add(o1);
                    }else {
                        list.add(this.getValue(e));
                    }
                }
                //对集合进行截取流程
                value = this.listSubList(list);
            }else {
                Element e = JsoupUtils.getElementIndex(element,selectSplit,indexSplit,this.must);
                if(this.clazz != null){
                    //对象类型
                    Object o1 = this.clazz.newInstance();
                    for (CrawlerFiledContainer child : this.children) {
                        value = child.fillHtmlObject(e, o1);
                    }
                }else {
                    //普通类型
                    value = this.getValue(e);
                }
            }
            //进行属性填充
            Method setMethod = this.getSetMethod(o.getClass());
            setMethod.invoke(o,value);
        }catch (IllegalAccessException | InstantiationException | InvocationTargetException exception){
            exception.printStackTrace();
        }
        return o;
    }

    /**
     * 获取属性的set方法
     * @param pClazz Class
     * @return Method
     */
    private Method getSetMethod(Class<?> pClazz){
        //set方法拼接
        String setName = "set" + this.fieldName.substring(0, 1).toUpperCase() + this.fieldName.substring(1);
        //获取类全部方法
        Method[] methods = pClazz.getMethods();
        //找打名称相同的set方法
        List<Method> setList = Arrays.stream(methods).filter(item -> item.getName().equals(setName)).collect(Collectors.toList());
        //得到参数只有一个的set方法
        Optional<Method> first = setList.stream().filter(item -> item.getParameterTypes().length == 1).findFirst();
        if (first.isPresent()){
            return first.get();
        }else {
            CrawlerException.error("未找到指定的单参数 " + setName + " 方法");
        }
        return null;
    }

    /**
     * 获取标签值 如果有attr则获取 没有就获取标签text值
     * @param element Element
     * @return String
     */
    private String getValue(Element element){
        if (this.attr != null){
            return element.attr(this.attr);
        }
        return element.text().trim();
    }


    /**
     * 对List进行截取
     * @param list 需要截取的List
     * @return List<Object>
     */
    private List<Object> listSubList(List<Object> list){
        //进行长度截取
        if (this.collectionIndex != null){
            String[] collectionIndexSplit = this.collectionIndex.split(";");
            int start = Integer.parseInt(collectionIndexSplit[0]);
            int end = Integer.parseInt(collectionIndexSplit[1]);
            return list.subList(start >= -1 ? 0 : start,end >= -1 ? list.size() : end);
        }
        return list;
    }
}
